import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
from collections import defaultdict
import json
from datetime import datetime

class UserPersonaManager:
    """
    用户画像管理系统
    功能：
    1. 角色分类管理（核心使用者/直接受益者/间接参与者）
    2. 画像要素模板管理
    3. 画像验证矩阵评估
    4. 风险识别与优先级计算
    5. 可视化呈现（角色关系矩阵、鱼骨图）
    """
    
    def __init__(self):
        # 初始化角色分类（文档第一部分）
        self.role_categories = {
            'core_user': {
                'name': '核心使用者',
                'subtypes': ['中小学教师(新手)', '中小学教师(资深)'],
                'frequency': '每日≥3次',
                'decision_weight': 5
            },
            'primary_beneficiary': {
                'name': '直接受益者',
                'subtypes': ['K12学生(重点班)', 'K12学生(普通班)'],
                'frequency': '每日≥5次',
                'decision_weight': 5
            },
            'secondary_participant': {
                'name': '间接参与者',
                'subtypes': ['教务主任(技术型)', '教务主任(行政型)'],
                'frequency': '每周2次',
                'decision_weight': 5
            }
        }
        
        # 画像模板结构（文档第二部分）
        self.persona_template = {
            'role_name': '',
            'demographics': {
                'age': '',
                'experience': '',
                'tech_level': '',
                'devices': []
            },
            'behavior': {
                'daily_tasks': [],
                'preferences': []
            },
            'needs': {
                'pain_points': [],
                'expectations': []
            },
            'constraints': {
                'technical': [],
                'performance': []
            }
        }
        
        # 存储所有画像数据
        self.personas = {}
        
        # 验证矩阵配置（文档第三部分）
        self.validation_matrix = {
            'requirement_coverage': {
                'method': 'RTM',
                'threshold': 0.85
            },
            'behavior_authenticity': {
                'method': '用户旅程地图',
                'threshold': 0.05
            },
            'technical_feasibility': {
                'method': 'A/B测试',
                'threshold': 0.9
            }
        }
        
        # 风险清单（文档第四部分）
        self.risk_register = [
            {'name': '教师角色生物识别抵触', 'mitigation': '准备替代登录方案', 'priority': '高'},
            {'name': '学生设备性能差异', 'mitigation': '制定分级渲染策略', 'priority': '中'}
        ]
        
        # 优先级计算权重（文档第四部分）
        self.priority_weights = {
            'user_coverage': 0.6,
            'usage_frequency': 0.3,
            'technical_difficulty': 0.1
        }

    def create_persona(self, role_type, subtype, ​**kwargs):
        """
        创建用户画像
        参数:
        - role_type: core_user/primary_beneficiary/secondary_participant
        - subtype: 对应的子类型
        - kwargs: 画像详细信息
        """
        if role_type not in self.role_categories:
            raise ValueError(f"无效的角色类型，可选: {list(self.role_categories.keys())}")
            
        if subtype not in self.role_categories[role_type]['subtypes']:
            raise ValueError(f"无效的子类型，可选: {self.role_categories[role_type]['subtypes']}")
        
        persona_id = f"{role_type}_{subtype}_{datetime.now().strftime('%Y%m%d')}"
        persona = self.persona_template.copy()
        
        # 更新基本信息
        persona['role_name'] = f"{self.role_categories[role_type]['name']}-{subtype}"
        
        # 更新详细属性
        for section in ['demographics', 'behavior', 'needs', 'constraints']:
            if section in kwargs:
                persona[section].update(kwargs[section])
        
        self.personas[persona_id] = persona
        return persona_id

    def validate_persona(self, persona_id):
        """
        验证画像质量（文档第三部分验证矩阵）
        返回通过/不通过及详细评估结果
        """
        if persona_id not in self.personas:
            raise ValueError("无效的画像ID")
            
        persona = self.personas[persona_id]
        results = {}
        
        # 需求覆盖度验证
        must_have_count = len([req for req in persona['needs']['expectations'] 
                             if 'must-have' in req.lower()])
        results['requirement_coverage'] = {
            'value': must_have_count / 3,  # 文档要求每个角色最多3个must-have
            'passed': must_have_count / 3 >= self.validation_matrix['requirement_coverage']['threshold']
        }
        
        # 行为真实性验证（模拟）
        results['behavior_authenticity'] = {
            'value': 0.03,  # 假设误差率3%
            'passed': 0.03 <= self.validation_matrix['behavior_authenticity']['threshold']
        }
        
        # 技术可行性验证（模拟）
        results['technical_feasibility'] = {
            'value': 0.92,  # 假设实现度92%
            'passed': 0.92 >= self.validation_matrix['technical_feasibility']['threshold']
        }
        
        # 总体是否通过
        results['overall_passed'] = all([v['passed'] for k, v in results.items()])
        
        return results

    def calculate_priority(self, requirement, user_coverage, usage_frequency, technical_difficulty):
        """
        计算需求优先级（文档第四部分决策模型）
        公式: 需求优先级 = 用户覆盖度(0.6) × 使用频率(0.3) × 技术难度(0.1)
        """
        score = (self.priority_weights['user_coverage'] * user_coverage +
                self.priority_weights['usage_frequency'] * usage_frequency +
                self.priority_weights['technical_difficulty'] * (1 - technical_difficulty))
        
        return {
            'requirement': requirement,
            'score': round(score, 2),
            'components': {
                'user_coverage': user_coverage,
                'usage_frequency': usage_frequency,
                'technical_difficulty': technical_difficulty
            }
        }

    def visualize_role_matrix(self):
        """
        生成角色关系矩阵图（文档第五部分可视化要求）
        """
        roles = list(self.role_categories.values())
        interactions = defaultdict(dict)
        
        # 模拟交互关系
        interactions['核心使用者']['直接受益者'] = '教学互动'
        interactions['核心使用者']['间接参与者'] = '数据汇报'
        interactions['直接受益者']['间接参与者'] = '成绩反馈'
        
        fig, ax = plt.subplots(figsize=(8, 6))
        
        # 创建矩阵数据
        matrix_data = pd.DataFrame(index=[r['name'] for r in roles],
                                  columns=[r['name'] for r in roles])
        
        for role1 in interactions:
            for role2 in interactions[role1]:
                matrix_data.loc[role1, role2] = 1
                matrix_data.loc[role2, role1] = 1
        
        matrix_data = matrix_data.fillna(0)
        
        # 绘制热力图
        cmap = cm.get_cmap('Blues')
        cax = ax.matshow(matrix_data, cmap=cmap, vmin=0, vmax=1)
        
        # 设置标签
        ax.set_xticks(range(len(roles)))
        ax.set_yticks(range(len(roles)))
        ax.set_xticklabels([r['name'] for r in roles], rotation=45)
        ax.set_yticklabels([r['name'] for r in roles])
        
        # 添加交互标签
        for i in range(len(roles)):
            for j in range(len(roles)):
                if i != j and matrix_data.iloc[i, j] == 1:
                    ax.text(j, i, interactions[roles[i]['name']].get(roles[j]['name'], ''),
                           ha='center', va='center', color='red')
        
        plt.title('用户角色关系矩阵图')
        plt.colorbar(cax)
        plt.tight_layout()
        return fig

    def generate_fishbone_diagram(self, persona_id):
        """
        生成痛点鱼骨图（特性要因图）
        """
        if persona_id not in self.personas:
            raise ValueError("无效的画像ID")
            
        persona = self.personas[persona_id]
        pain_points = persona['needs']['pain_points']
        
        fig, ax = plt.subplots(figsize=(10, 6))
        
        # 主箭头
        ax.arrow(0.1, 0.5, 0.8, 0, head_width=0.02, head_length=0.02, fc='k', ec='k')
        ax.text(0.5, 0.55, persona['role_name'] + '痛点分析', 
                ha='center', va='bottom', fontsize=12)
        
        # 分类骨（模拟常见分类）
        categories = ['技术', '流程', '人员', '环境']
        angles = [30, 15, -15, -30]
        
        for i, (category, angle) in enumerate(zip(categories, angles)):
            # 画主骨
            rad = angle * (3.14 / 180)
            ax.arrow(0.3, 0.5, 0.2 * np.cos(rad), 0.2 * np.sin(rad), 
                    head_width=0.01, head_length=0.01, fc='k', ec='k')
            ax.text(0.3 + 0.25 * np.cos(rad), 0.5 + 0.25 * np.sin(rad), 
                    category, ha='center', va='center')
            
            # 添加痛点（均匀分布）
            if i < len(pain_points):
                ax.text(0.3 + 0.15 * np.cos(rad), 0.5 + 0.15 * np.sin(rad), 
                        pain_points[i], ha='center', va='center', fontsize=10)
        
        ax.set_xlim(0, 1)
        ax.set_ylim(0, 1)
        ax.axis('off')
        plt.tight_layout()
        return fig

    def export_persona_report(self, persona_id, format='json'):
        """
        导出画像报告（支持JSON和Markdown格式）
        """
        if persona_id not in self.personas:
            raise ValueError("无效的画像ID")
            
        persona = self.personas[persona_id]
        validation = self.validate_persona(persona_id)
        
        if format == 'json':
            report = {
                'persona': persona,
                'validation_results': validation,
                'timestamp': datetime.now().isoformat()
            }
            return json.dumps(report, indent=2, ensure_ascii=False)
            
        elif format == 'markdown':
            md = f"# 用户画像报告: {persona['role_name']}\n\n"
            md += f"​**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M')}\n\n"
            
            # 人口统计
            md += "## 人口统计\n"
            for k, v in persona['demographics'].items():
                md += f"- {k}: {v}\n"
            
            # 行为特征
            md += "\n## 行为特征\n"
            for item in persona['behavior']['daily_tasks']:
                md += f"- {item}\n"
            
            # 核心诉求
            md += "\n## 核心诉求\n"
            md += "### 痛点:\n"
            for pain in persona['needs']['pain_points']:
                md += f"- {pain}\n"
            
            md += "\n### 期望:\n"
            for exp in persona['needs']['expectations']:
                md += f"- {exp}\n"
            
            # 验证结果
            md += "\n## 验证结果\n"
            for k, v in validation.items():
                if k != 'overall_passed':
                    md += f"- {k}: {'通过' if v['passed'] else '未通过'} (值: {v['value']})\n"
            
            return md
            
        else:
            raise ValueError("不支持的格式，可选: json/markdown")


# 示例使用
if __name__ == "__main__":
    manager = UserPersonaManager()
    
    # 创建教师画像（文档第二部分示例）
    teacher_id = manager.create_persona(
        role_type='core_user',
        subtype='中小学教师(资深)',
        demographics={
            'age': '32岁',
            'experience': '7年教龄',
            'tech_level': '中等信息化水平',
            'devices': ['Surface Pro', 'Android手机']
        },
        behavior={
            'daily_tasks': [
                '每日批改作业3小时',
                '70%时间用于制作课件'
            ],
            'preferences': [
                '每月组织2次在线测验',
                '偏好可视化数据报表'
            ]
        },
        needs={
            'pain_points': [
                '作业批改耗时',
                '无法快速定位知识薄弱点'
            ],
            'expectations': [
                '自动批改基础题型(must-have)',
                '生成错题知识点关联图(must-have)'
            ]
        },
        constraints={
            'technical': ['拒绝使用需要专用外设的教学工具'],
            'performance': ['要求所有操作能在10秒内完成响应']
        }
    )
    
    # 验证画像
    validation_results = manager.validate_persona(teacher_id)
    print(f"画像验证结果: {'通过' if validation_results['overall_passed'] else '未通过'}")
    
    # 计算需求优先级
    priority = manager.calculate_priority(
        requirement='自动作业批改',
        user_coverage=0.9,  # 90%教师需要
        usage_frequency=0.8,  # 高频使用
        technical_difficulty=0.3  # 中等技术难度
    )
    print(f"\n需求优先级评估: {priority}")
    
    # 生成可视化图表
    matrix_fig = manager.visualize_role_matrix()
    matrix_fig.savefig('role_matrix.png')
    
    fishbone_fig = manager.generate_fishbone_diagram(teacher_id)
    fishbone_fig.savefig('pain_points_fishbone.png')
    
    # 导出报告
    json_report = manager.export_persona_report(teacher_id, format='json')
    with open('teacher_persona.json', 'w', encoding='utf-8') as f:
        f.write(json_report)
    
    md_report = manager.export_persona_report(teacher_id, format='markdown')
    with open('teacher_persona.md', 'w', encoding='utf-8') as f:
        f.write(md_report)